﻿// Ŭnicode please
#include "SRSceneNodeVisitor.h"
#include "SRScene.h"
#include "SRGLinc.h"
#include "SRGLMachine.h"
#include "SRModel.h"
#include "SRLight.h"
#include "SRPrimitiveModel.h"

using std::vector;

namespace sora
{
	GLES1Renderer::GLES1Renderer()
		: lightCodeStack_(new LightCodeStack())
	{
	}
	GLES1Renderer::~GLES1Renderer()
	{
	}
	void GLES1Renderer::render(SceneNode *node)
	{
		//scene graph시작점에서 모델행렬 초기화
		//for ar lib
		//glMatrixMode(GL_MODELVIEW);
		//glLoadIdentity();
		node->accept(*this);

		/*
		//빛 적용한거 해제하기
		//light node의 적용범위를 light node가 들어있는 scene node group로 할지
		//아니면 light node가 적용된것부터 전체로 할지 정책이 확정되지 않았다
		//아래의 코든느 lignt node적용후 전역에 적용되는 정책을 쓸 경우 
		//렌더링 종료후 사용된 light code를 회수하는 작업을 수행한다
		while(lightCodeStack_->delimExist() == true)
		{
			std::vector<int> usedLightCodeList = lightCodeStack_->lastLightCodeList();
			for(std::size_t i = 0 ; i < usedLightCodeList.size() ; i++)
			{
				int code = usedLightCodeList[i];
				glDisable(code);
			}
			lightCodeStack_->popDelim();
		}
		*/
	}
	void GLES1Renderer::visit(SceneNodeGroup *node)
	{
		//변환
		vector<Transformation*>::const_iterator transformationBeginIter = node->transformationListBegin();
		vector<Transformation*>::const_iterator transformationEndIter = node->transformationListEnd();
		vector<Transformation*>::const_iterator transformationIter;

		glPushMatrix();

		//행렬변환 적용하기
		for(transformationIter = transformationBeginIter ; transformationIter != transformationEndIter ; transformationIter++)
		{
			Transformation *trans = *transformationIter;
			switch(trans->type())
			{
			case TransformationTypeTranslate:
				glTranslatef(trans->translateX(), trans->translateY(), trans->translateZ());
				break;
			case TransformationTypeScale:
				glScalef(trans->scaleX(), trans->scaleY(), trans->scaleZ());
				break;
			case TransformationTypeRotate:
				{
					float xrot = trans->rotateX();
					float yrot = trans->rotateY();
					float zrot = trans->rotateZ();
					if(xrot == 0 && yrot == 0 && zrot == 0)
						;
					else if(xrot != 0 && yrot == 0 && zrot == 0)
						glRotatef(xrot, 1, 0, 0);	//x rotate
					else if(xrot == 0 && yrot != 0 && zrot == 0)
						glRotatef(yrot, 0, 1, 0);	//y rotate
					else if(xrot == 0 && yrot == 0 && zrot != 0)
						glRotatef(zrot, 0, 0, 1);	//z rotate
					else
						SR_ASSERT(!"not support complex axis rotate");
				}
				break;
			}
		}

		//빛 적용하기
		for(int i = 0 ; i < node->numLight() ; i++)
		{
			LightNode *light = node->light(i);
			light->accept(*this);
		}
		lightCodeStack_->pushDelim();
		if(lightCodeStack_->numRemain() == LightCodeStack::MaxLight)
			glDisable(GL_LIGHTING);
		else
			glEnable(GL_LIGHTING);
		
		//자식 처리
		for(int i = 0 ; i < node->numChild() ; i++)
		{
			SceneNode *child = node->child(i);
			child->accept(*this);
		}

		//빛 적용한거 해제하기
		std::vector<int> usedLightCodeList = lightCodeStack_->lastLightCodeList();
		for(std::size_t i = 0 ; i < usedLightCodeList.size() ; i++)
		{
			int code = usedLightCodeList[i];
			glDisable(code);
		}
		lightCodeStack_->popDelim();

		//변환 복구
		glPopMatrix();
	}
	void GLES1Renderer::visit(LightNode *node)
	{
		//빛 코드 얻기 + 얻은거 저장하기. scene node group단위로 몇개나 사용되었나를
		//알아야복구할수 있다
		int lightCode = lightCodeStack_->pop();
		glEnable(lightCode);
		glEnable(GL_LIGHTING);

		const Light &light = node->light();
		color4 &color = const_cast<color4&>(light.color());
		float *colorPtr = color.pointer();
		matsu::vec4 &pos = const_cast<matsu::vec4&>(light.pos());
		float *posPtr = pos.pointer();

		switch(light.type())
		{
		case LightTypeAmbient:
			glLightfv(lightCode, GL_AMBIENT, colorPtr);
			break;
		case LightTypeDiffuse:
			glLightfv(lightCode, GL_DIFFUSE, colorPtr);
			glLightfv(lightCode, GL_POSITION, posPtr);
			break;
		default:
			SR_ASSERT(!"Not support other light yet");
			break;
		}
	}
	void GLES1Renderer::visit(ModelNode *node)
	{
		sora::gles1::drawModel(node->model());
	}

}
